/**
 * 异步导入模式： 回调队列
 * 最简化版本
 * 1. 不考虑重复引入
 * 2. 定义模块，不引入额外依赖
 * 3. require只引入一个模块
 * 
 * 同步模式+订阅模式(被订阅的物品通过订阅列表 通知 订阅人)
 */
(function(globalObj){
    const ModulesMap = {}, 
    STATUS_SET = {
        INIT:'init',
        LOADING:'loading',
        LOADED: 'loaded',
    }

    function define(moduleName='', callBack){
        if(!moduleName){
            return
        }
        
        if(ModulesMap[moduleName]){
            console.warn(`依赖 ${moduleName}, 已存在，请勿重复定义`);
            return
        }

        ModulesMap[moduleName] = {
            status: STATUS_SET.INIT,
            callBack: callBack,
            result: undefined, //模块返回值
            loadedQueue: [  ], //加载完成后的回调队列
        }
    }

    function loadDept(moduleName,fn){
        ModulesMap[moduleName].status = STATUS_SET.LOADING
        fn&&ModulesMap[moduleName].loadedQueue.push(fn)

        setTimeout(()=>{
            const result = ModulesMap[moduleName].callBack&&ModulesMap[moduleName].callBack()
            ModulesMap[moduleName].status = STATUS_SET.LOADED
            // 存储结果，方便下次调用
            ModulesMap[moduleName].result = result
            // 加载完成，执行回调对队列
            for(let fn of ModulesMap[moduleName].loadedQueue){
                fn(result)
            }
        },2000)
    }

    function require(depName='', fn){
            
        if(!ModulesMap[depName]){
            // 不存在依赖,报错
            console.error(`依赖 ${depName}, 不存在`);
        }else if(ModulesMap[depName]&&ModulesMap[depName].status==STATUS_SET.INIT){
            // 存在依赖加载，但是初始状态，加载依赖
            loadDept(depName, fn)

        }else if(ModulesMap[depName]&&ModulesMap[depName].status==STATUS_SET.LOADING){
            // 存在依赖，但是正在加载中，则将回调 加入成功队列
            ModulesMap[depName].loadedQueue.push(fn)

        }else if(ModulesMap[depName]&&ModulesMap[depName].status==STATUS_SET.LOADED){
            // 存在依赖,且加载已经完成，执行回调
            fn( ModulesMap[depName].callBack() )
        }

    }

    globalObj.define = define
    globalObj.require = require
})( global )


define('A',function(){
    console.log('A define invoked');

    return {
        methodA: ()=>{ console.warn('this is methodA'); }
    }
})

require('A', function(A){
    console.log('require A invoke',A);
})
